package ru.spb.osll.myfit.server.parser;

import java.util.Vector;

import ru.spb.osll.myfit.common.Table;
import ru.spb.osll.myfit.common.TableCell;
import ru.spb.osll.myfit.common.TableCellResult;
import ru.spb.osll.myfit.common.TableStyle;
import ru.spb.osll.myfit.util.Pair;
import fit.Parse;

public class TableParser {
	private static String TABLE_END_TAG = "</table";
	private static String TABLE_ROW_TAG = "<tr";
	private static String TABLE_CELL_TAG = "<td";
	private static String TABLE_TAG = "<table";
	private static String CELL_CLASS_ERROR = "class=\"error\"";
	private static String CELL_CLASS_FAIL = "class=\"fail\"";
	private static String CELL_CLASS_PASS = "class=\"pass\"";
	private static String EXCEPTION_PREFIX = "<hr><pre><div class=\"fit_stacktrace\">";
	private static String EXCEPTION_SUFFIX = "</div></pre>";
	private static String IMPORT_TABLE = "Import";

	private TableCellResult tableResult = TableCellResult.IGNORE;
	private String tableException = null;
	
	private TableCellResult rowResult = TableCellResult.IGNORE;
	private String rowException = null;

	public Table parse(Parse parse) {
		Table result = new Table(TableStyle.UNKNOWN_FIXTURE);
		parse(parse, result);

		if (result.getData().size() > 0) {
			if (result.getData().get(0).size() > 0) {
				if (result.getData().get(0).get(0).getText().equals(
						IMPORT_TABLE)) {
					result = null;
				}
			}
		}

		return result;
	}

	private boolean parse(Parse table, Table result) {
		boolean tableEndReached = false;
		
		if (table.parts == null) {
			parseLeave(table, result);
			tableEndReached = parseMore(table, result);
		} else {
			tableEndReached = parseParts(table, result);
			if (!tableEndReached) {
				tableEndReached = parseMore(table, result);
			} 
		}
		
		return tableEndReached;
	}

	private void parseLeave(Parse table, Table result) {
		proccessTag(table, result);
	}

	private boolean parseMore(Parse table, Table result) {
		boolean tableEndReached = false;
		
		if ((table.more != null)) {
			tableEndReached = parse(table.more, result);
		}

		return tableEndReached;
	}

	private boolean parseParts(Parse table, Table result) {
		boolean tableEndReached = false;
		proccessTag(table, result);
		tableEndReached = parse(table.parts, result);
		tableEndReached = tableEndReached || isTableEndReached(table, result);

		return tableEndReached;
	}

	private void proccessTag(Parse table, Table result) {
		if(table.tag.startsWith(TABLE_TAG)) {
			tableException = null;
			tableResult = getTableCellResult(table.tag);
			if(tableResult == TableCellResult.EXCEPTION) {
				Pair<String, String> pair = extractException(table.body);
				tableException = pair.getSecond();
			}
		} else if (table.tag.startsWith(TABLE_ROW_TAG)) {
			rowException = null;
			rowResult = getTableCellResult(table.tag);
			if(rowResult == TableCellResult.EXCEPTION) {
				Pair<String, String> pair = extractException(table.body);
				rowException = pair.getSecond();
			}
			result.getData().add(new Vector<TableCell>());
		} else if (table.tag.startsWith(TABLE_CELL_TAG)) {
			TableCellResult cellResult = getTableCellResult(table.tag);
			String text = null;
			String exception = null;

			if (cellResult == TableCellResult.EXCEPTION) {
				Pair<String, String> pair = extractException(table.body);
				text = pair.getFirst();
				exception = pair.getSecond();
			} else if(cellResult == TableCellResult.IGNORE) {
				if((rowResult) != null && (rowResult == TableCellResult.IGNORE)) {
					cellResult = tableResult;
					exception = tableException;
				} else {
					cellResult = rowResult;
					exception = rowException;
				}
				text = table.text();
			} else {
				text = table.text();
			}

			TableCell cell = new TableCell(text);
			cell.setTestResult(cellResult);
			if (exception != null) {
				cell.setTooltip(exception);
			}
			result.getData().lastElement().add(cell);
		}
	}

	private boolean isTableEndReached(Parse table, Table result) {
		return table.end.startsWith(TABLE_END_TAG);
	}

	private Pair<String, String> extractException(String fullText) {
		Pair<String, String> pair = new Pair<String, String>(null, null);
		int pos = fullText.lastIndexOf(EXCEPTION_PREFIX);
		if (pos > 0) {
			pair.setFirst(fullText.substring(0, pos));
			int endPos = fullText.indexOf(EXCEPTION_SUFFIX);
			if (endPos > 0) {
				pair.setSecond(fullText.substring(pos
						+ EXCEPTION_PREFIX.length(), endPos));
			}
		} else {
			pair.setFirst(fullText);
		}

		return pair;
	}

	private TableCellResult getTableCellResult(String tag) {
		TableCellResult cellResult = TableCellResult.IGNORE;

		if (tag.contains(CELL_CLASS_ERROR)) {
			cellResult = TableCellResult.EXCEPTION;
		} else if (tag.contains(CELL_CLASS_FAIL)) {
			cellResult = TableCellResult.FAIL;
		} else if (tag.contains(CELL_CLASS_PASS)) {
			cellResult = TableCellResult.PASS;
		}

		return cellResult;
	}
}
